package de.hwrberlin.remo.algorithm;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import de.hwrberlin.expertsystem.util.ModelEditingHelper;
import de.hwrberlin.remo.algorithm.steps.AlgorithmStep;
import de.hwrberlin.remo.model.KnowledgeBase;

/**
 * This class describes an abstract inferenz algorithm within the application.
 * The class is used in the algorithm extension point and each available algorithm
 * has to subclass this class.  
 * 
 * @author Mario Sänger (IT 09)
 * @version 1.0
 *
 */
public abstract class InferenzAlgorithm {

	private List<AlgorithmListener> listeners = new ArrayList<AlgorithmListener>();
	protected ModelEditingHelper editingHelper;
	protected UserInterface userInterface;
	
	private Logger logger;

	/////////////////////////
	/* Execution method    */
	
	/**
	 * Initializes and starts the algorithm with the given knowledge base.
	 * This method is supposed to be called by an client class.
	 * 
	 */
	public void start(KnowledgeBase base) {
		AlgorithmInitializer initializer = getInitializer();
		
		if(initializer != null) {
			initializer.initializeAlgorithm(this, base);
		}
		
		run(base);
	}
	
	/////////////////////////
	/* Abstract methods    */

	/**
	 * Returns an initializer of the algorithm.
	 */
	public abstract AlgorithmInitializer getInitializer();
	
	/**
	 * Runs the algorithm with the given knowledge base.
	 * This method is used internally and is not supposed 
	 * to be called by other classes.
	 * 
	 * @param base Knowledge base
	 */
	protected abstract void run(KnowledgeBase base);
	
	/////////////////////////
	/* Getter / Setter     */
	
	public ModelEditingHelper getEditingHelper() {
		return editingHelper;
	}

	public void setEditingHelper(ModelEditingHelper editingHelper) {
		this.editingHelper = editingHelper;
	}

	public UserInterface getUserInterface() {
		return userInterface;
	}

	public void setUserInterface(UserInterface userInterface) {
		this.userInterface = userInterface;
	}
	
	protected Logger getLogger() {
		if(logger == null) {
			logger = Logger.getLogger(getClass());
		}
		
		return logger;
	}
	
	/////////////////////////////////
	/* Algorithm listener handling */
	
	public void registerListener(AlgorithmListener listener) {
		if(!listeners.contains(listener)) {
			listeners.add(listener);
		}
	}
	
	public void unregisterListener(AlgorithmListener listener) {
		if(listeners.contains(listener)) {
			listeners.remove(listener);
		}
	}
	
	protected void fireStepFinishedEvent(AlgorithmStep step) {
		for(AlgorithmListener listener : listeners) {
			listener.stepFinished(step);
		}
	}
}